/*
  Copyright (C) 2011, Kyungjoo Kim
  
  This file is part of LINAL (LINear ALgebra)
  
  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Also add information on how to contact you by electronic and paper mail.
  
  
  Kyungjoo Kim
  iamkyungjoo@gmail.com
*/
#include "linal/common.hxx"
#include "linal/util.hxx"

#include "linal/format.hxx"

#include "linal/operation.hxx"

#include "linal/device/host/operation.hxx"

namespace linal {

  static int apply_q2_l( int trans, int direct,
                         Hier_ D, Hier_ T, Hier_ W, Hier_ C, Hier_ E );

  int apply_q2_l( int trans, int direct, 
                  Hier_ D, Hier_ T, Hier_ W, Hier_ C, Hier_ E ) {
    
    if (T.get_m() && T.get_n()) {

      void
        *buf_D = D.get_buffer(),
        *buf_T = T.get_buffer(),
        *buf_W = W.get_buffer(),
        *buf_C = C.get_buffer(),
        *buf_E = E.get_buffer();

      int
        cs_D = D.get_cs(),
        cs_T = T.get_cs(),
        cs_W = W.get_cs(),
        cs_C = C.get_cs(),
        cs_E = E.get_cs();

      for (int i=0;i<T.get_m();++i) {

        for (int j=0;j<W.get_n();++j) {

#pragma omp task firstprivate(i,j)
          {
            FLA_Apply_Q2_UT_internal( FLA_LEFT, FLA_CONJ_TRANSPOSE,
                                      FLA_FORWARD, FLA_COLUMNWISE,
                                      LINAL_ELEM_FLA(_D, i,0), 
                                      LINAL_ELEM_FLA(_T, i,0),
                                      LINAL_ELEM_FLA(_W, 0,j), 
                                      LINAL_ELEM_FLA(_C, 0,j),
                                      LINAL_ELEM_FLA(_E, i,j),
                                      fla_apq2ut_cntl_leaf );
          }
        }

#pragma omp taskwait

      }
    }
    return true;
  }

  int apply_q2(int side, int trans, int direct, int storev,
               Hier_ D, Hier_ T, Hier_ W, Hier_ C, Hier_ E) {
    
    switch (side) {
    case FLA_LEFT:
      {
        apply_q2_l( trans, direct, D, T, W, C, E );
        break;
      }
    case FLA_RIGHT:
      {
        break;
      }
    }
    return true;
  }
}
